/*-----------------------------------------------File Info------------------------------------------------
** File Name:               main.c  
** Last modified date:      2016.07.22
** Last version:            V0.1
** Description:             
**--------------------------------------------------------------------------------------------------------            
** Created date:            2016.09.07
** author:                  YLY
** Version:                 V0.1
** Descriptions:            C程序入口
**--------------------------------------------------------------------------------------------------------
*/

/* 逻辑如下：
*	MCU启动时，默认启动bootload
*	在bootload中开请看门够。
*	读用户数据FLASH，检查是否在升级状态：
*		如果正常AP工作模式，直接跳转，如果跳转不成本，停留在bootload,检查升级
*		如果是其它模式，初始化bootload所需外设，检查升级，直到升级成本，可以正常跳转。
*	在bootload中每5秒未应答，会超时检查升级状态：
*		如果是正常AP工作状态，跳转至AP，如果跳转失败，重新跳转回bootload
*		如果是其它状态，重新跳转回bootload或者重启MCU，一直检查更新，直到成功。
*	
*/
/*************************************************************
* 	include 
* 	头文件	
*************************************************************/
#include <stdio.h>
#include "loadMain.h"

#include "bspUART.h"
#include "bspFMC.h"
#include "bspTimer.h"
#include "bootloader.h"
#include "loadProtocol.h"
#include "appGpio.h"


bool gUpdating = false;
volatile tsIsp gtIsp;

/* 必需初始化的GPIO */
//tsCfgGpio gtCfgIntOut = INT_OUT;


/* 系统定时器中断向量 */
#define SYSTEM_TIME_ISR  SysTick_Handler
 
/* 系统定时器控制寄存器 */
#define SYSTICK_CTRL		( ( volatile uint32_t *) 0xe000e010 )
	
/* 系统定时器重载值 */
#define SYSTICK_LOAD		( ( volatile uint32_t *) 0xe000e014 )

/* 系统定时器值 */
#define SYSTICK_VAL			( ( volatile uint32_t *) 0xe000e018 )
	
/* 当前值寄存器 */
#define SYSTICK_CALIR		( ( volatile uint32_t *) 0xe000e01C )
	
/* 中断状态控制寄存器 */
#define SYSINT_CTRL			( ( volatile uint32_t *) 0xe000ed04 )
	
#define SYSTICK_CLK_BIT			0x00000004	/* 使用内核时钟作为TICK时钟源 */
#define SYSTICK_INT_BIT			0x00000002	/* 使能TICK中断 */
#define SYSTICK_ENABLE_BIT		0x00000001	/* 使能TICK */

/* 中断优先级设置 */
#define SYSPRI2			    ( ( volatile uint32_t *) 0xe000ed20 )
	
/* 时钟频率,注意是TICK时钟源的频率,非OSC频率 */
#define SYS_CLOCK_HZ    	( unsigned long ) SystemCoreClock	//rcu_clock_freq_get(CK_SYS)	
	
	
/* 系统定时器频率（Hz）最小为1Hz,最大不超过1000Hz,推荐频率100Hz~1000Hz*/
#define TICK_RATE_HZ   		1000u

/**
 *  系统定时器初始化
 */
void sysTickInit(void)
{
	*(SYSTICK_CTRL) = 0;
	
	/* 装载TICK定时器初值 */	
	*(SYSTICK_LOAD) = (SYS_CLOCK_HZ/TICK_RATE_HZ) - 1UL; 
	
	/*  写入任意值 清零*/	
	*(SYSTICK_VAL) = 0;
	
	/* 使能ITCK定时器 */	
	*(SYSTICK_CTRL) = SYSTICK_CLK_BIT | SYSTICK_INT_BIT | SYSTICK_ENABLE_BIT;	
}
/**
 *  系统定时器初始化
 */
void sysTickStop(void)
{		
	/* 使能ITCK定时器 */	
	*(SYSTICK_CTRL) = 0x00000000;	
}

/**
 *  看门狗初始化,看门狗1S喂狗一次
 */
void wdtInit(void)
{
    /* enable IRC40K */
    rcu_osci_on(RCU_IRC40K);
    /* wait till IRC40K is ready */
    rcu_osci_stab_wait(RCU_IRC40K);	

    /* enable write access to FWDGT_PSC and FWDGT_RLD registers.
    FWDGT counter clock: 40KHz(IRC40K) / 64 = 0.625 KHz =1.6mS */
    fwdgt_config(4000,FWDGT_PSC_DIV64);//1.6*4000 = 6.4S
    fwdgt_enable();
}

/**
 *  看门狗反初始化
 */
void wdtClose(void)
{
    /* enable IRC40K */
    rcu_osci_off(RCU_IRC40K);
	FWDGT_CTL = 0;
}

/**
 *  喂狗
 */
void clrWdt(void)
{
	fwdgt_counter_reload();
}



void setWorkSta(teStatus status)
{
	static tsUserData  tUserData;
	tsUserData	*ptUserData = (tsUserData	*)USER_DATA_ADDR;
	
	gtIsp.status = status;	
	
	if(gtIsp.status == ISP_UPDATEING)	//置升级中标识
	{
		if(ptUserData->apromUpdateSta != LDROM_UIPDATEING)	//检查标识
		{
			memcpy((void *)&tUserData, (void *)ptUserData, sizeof(tsUserData));
			tUserData.apromUpdateSta = LDROM_UIPDATEING;
			
			fmcErasePages((uint32_t)ptUserData, 1);									//擦除FLASH
			fmcProgram((uint32_t)ptUserData, (uint8_t *)&tUserData, sizeof(tsUserData));		//保存密码	
		}
	}	
}

/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{	
	static uint8_t count = 0;
	static tsCfgUart tgCfgUart = DBG_UART;
	static uint8_t updateInquiryCount = 0;
	tsUserData	*ptUserData = (tsUserData	*)USER_DATA_ADDR;

	gpioInit();			
	
	wdtInit();	//初始化看门狗，如果AP跳转后程序异常，MCU会重启
	
	GLOBAL_DBG("\r\n**********( bootload-%s )*************\r\n",BOOTLOAD_VER);
	
	if(ptUserData->apromUpdateSta == APROM_NONE_UPDATE ||	//未升级，直接跳转到AP
	   ptUserData->userMark != USER_DATA_MARK)				//FLASH 未初始化，第一次烧程序，直接跳转到AP
	{
		jumpToApplication();		//如果跳转失败会向下运行	
	}
	GLOBAL_DBG("**********updataing**********\r\n");
	protocolInit();				//通讯初始化
	
	requestStartUpdata();		//请求升级
	setWorkSta(ISP_REQUEST);
	
	sysTickInit();		//用做定时器
	count = 0;
	while(1)
	{	
		clrWdt();		
		if(gtIsp.time > UPDATE_REQUEST_INTERVAL)	//升级超时
		{
			GLOBAL_DBG("timeout\r\n");
			if(gtIsp.status == ISP_UPDATEING)	//设备在升级中,如果升级了部分数据，防止变砖，不能直接跳到APROM
			{
				requestStartUpdata();	//升级超时再次请求升级
			}
			else if(++count > 30)	//5次后跳转到APROM
			{
				jumpToApplication();			//未升级过，跳转到AP
				/* 运行到此处说明跳转失败，重启MCU或跳转到bootloader */
				jumpToBootloader();
			}
			gtIsp.time = 0;
		}	
		if(protocolProcessing() == true)	//接收数据
			gtIsp.time = 0;					//清除超时
	}
}

void SysTick_Handler(void)	/* 1mS SysTick_Handler */
{
	if(gtIsp.time < 0xffff)
		gtIsp.time++;
}

/**
  * @brief  This function handles Hard Fault exception.
  * @param  None
  * @retval None
  */
void HardFault_Handler(void)
{
  /* Go to infinite loop when Hard Fault exception occurs */
	GLOBAL_ERR("!HardFault,PSP=0x%x,MSP=0x%x\r\n",__get_PSP(),__get_MSP());/* 获取SP的值 */	
	while (1);
}


